#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <unistd.h>
#include <xf86drm.h>
#include <xf86drmMode.h>

#define DRM_DEVICE                                                             \
    "/dev/dri/card0" // DRM 设备节点（通常是 card0 或 renderD128）
#define COLOR_RED 0xFF0000FF   // ARGB 格式（红色）
#define COLOR_GREEN 0xFF00FF00 // ARGB 格式（绿色）
#define COLOR_BLUE 0xFFFF0000  // ARGB 格式（蓝色）

void print_crtc_info(int fd, uint32_t crtcId)
{
    drmModeCrtc* crtc;
    drmModeModeInfo crtcMode;
    // 4. 获取当前 CRTC（显示控制器）
    crtc = drmModeGetCrtc(fd, crtcId);
    if (crtc)
    {
        crtcMode = crtc->mode;
        printf("\t\tCRTC ID=%d, width=%d, height=%d crtcMode=%s "
               "htotal=%d vtotal=%d hdisplay=%d vdisplay=%d\n",
               crtc->crtc_id, crtc->width, crtc->height, crtcMode.name,
               crtcMode.htotal, crtcMode.vtotal, crtcMode.hdisplay,
               crtcMode.vdisplay);

        drmModeFreeCrtc(crtc);
    }
    else
    {
        perror("Failed to get CRTC");
    }
}

void print_all_crtcs_info(int fd, drmModeRes* res)
{

    drmModeConnector* conn;

    drmModeEncoderPtr encoder;
    //drmModeCrtc* crtc;
    //drmModeModeInfo crtcMode;

    for (int i = 0; i < res->count_connectors; i++)
    {
        conn = drmModeGetConnector(fd, res->connectors[i]);

        if (conn->connection == DRM_MODE_CONNECTED)
        {

            printf("Found connected connector: ID=%d\n", conn->connector_id);

            encoder = drmModeGetEncoder(fd, conn->encoder_id);

            if (encoder)
            {
                printf("\tEncoder ID=%d, CRTC ID=%d\n", encoder->encoder_id,
                       encoder->crtc_id);

                print_crtc_info(fd, encoder->crtc_id);

                drmModeFreeEncoder(encoder);
            }
        }
        else
        {
            printf("connector (ID=%d) is not connected: \n",
                   conn->connector_id);

            for (int i = 0; i < res->count_crtcs; i++)
            {
                uint32_t crtcId = res->crtcs[i];
                print_crtc_info(fd, crtcId);
            }
        }

        drmModeFreeConnector(conn);
    }
}

int main()
{
    int fd;
    drmModeRes* res;
    drmModeConnector* conn;

    drmModeEncoderPtr encoder;
    drmModeCrtc* crtc;
    drmModeModeInfo crtcMode;
    uint32_t fb_id;
    uint32_t* framebuffer;
    struct drm_mode_create_dumb create_req = {0};
    struct drm_mode_map_dumb map_req = {0};
    int result = -1; // 程序最终的返回结果

    // 1. 打开 DRM 设备
    fd = open(DRM_DEVICE, O_RDWR);
    if (fd < 0)
    {
        perror("Failed to open DRM device");
        goto openFailed;
    }

    // 2. 获取 DRM 资源（显示器、CRTC、连接器等）
    res = drmModeGetResources(fd);
    if (!res)
    {
        perror("Failed to get DRM resources");
        goto releaseResources;
    }

    print_all_crtcs_info(fd, res);

    // 3. 找到第一个可用的连接器（显示器）
    int i;
    for (i = 0; i < res->count_connectors; i++)
    {
        conn = drmModeGetConnector(fd, res->connectors[i]);

        if (conn->connection == DRM_MODE_CONNECTED)
        {

            printf("Found connected connector: ID=%d\n", conn->connector_id);

            encoder = drmModeGetEncoder(fd, conn->encoder_id);

            if (encoder)
            {
                printf("Encoder ID=%d, CRTC ID=%d\n", encoder->encoder_id,
                       encoder->crtc_id);

                // 4. 获取当前 CRTC（显示控制器）
                crtc = drmModeGetCrtc(fd, encoder->crtc_id);
                if (crtc)
                {
                    crtcMode = crtc->mode;
                    printf("CRTC ID=%d, width=%d, height=%d crtcMode=%s "
                           "htotal=%d vtotal=%d hdisplay=%d vdisplay=%d\n",
                           crtc->crtc_id, crtc->width, crtc->height,
                           crtcMode.name, crtcMode.htotal, crtcMode.vtotal,
                           crtcMode.hdisplay, crtcMode.vdisplay);

                    break;
                }
                else
                {
                    perror("Failed to get CRTC");
                }

                drmModeFreeEncoder(encoder);
            }
        }

        drmModeFreeConnector(conn);
    }

    if (!crtc)
    {
        fprintf(stderr, "No active connector found!\n");
        goto releaseResources;
    }

    crtc->width=1918;
    crtc->height=903;
//    crtc->mode.hdisplay = crtc->width;
//    crtc->mode.vdisplay = crtc->height;
    crtc->mode.htotal = 2068;
    crtc->mode.vtotal = 1053;


    printf("final width = %d, height = %d\n",crtc->width,crtc->height);
    

    // 5. 通过 GEM 分配显存对象，创建一个 dumb buffer（帧缓冲区）
    create_req.width = crtc->width;
    create_req.height = crtc->height;
    create_req.bpp = 32; // 32-bit ARGB

    if (drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_req) < 0)
    {
        perror("Failed to create dumb buffer");

        goto releaseCrtc;
    }

    // 6. 映射 dumb buffer 到用户空间(从GPU显存映射到CPU可以访问)
    map_req.handle = create_req.handle;
    if (drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &map_req) < 0)
    {
        perror("Failed to map dumb buffer");
        goto releaseCrtc;
    }

    framebuffer = mmap(0, create_req.size, PROT_READ | PROT_WRITE, MAP_SHARED,
                       fd, map_req.offset);
    if (framebuffer == MAP_FAILED)
    {
        perror("Failed to mmap dumb buffer");
        goto releaseCrtc;
    }

    // 7. 将 GEM 对象转换为 Framebuffer，创建一个 framebuffer 对象
    if (drmModeAddFB(fd, crtc->width, crtc->height, 24, 32, create_req.pitch,
                     create_req.handle, &fb_id) < 0)
    {
        perror("Failed to add framebuffer");
        goto munmapFramebuffer;
    }


    // 8. 绘制一个彩色矩形
    for (uint32_t y = 0; y < crtc->height; y++)
    {
        for (uint32_t x = 0; x < crtc->width; x++)
        {
            if (x < crtc->width / 3)
            {
                framebuffer[y * crtc->width + x] = COLOR_RED;
            }
            else if (x < 2 * crtc->width / 3)
            {
                framebuffer[y * crtc->width + x] = COLOR_GREEN;
            }
            else
            {
                framebuffer[y * crtc->width + x] = COLOR_BLUE;
            }
        }
    }

 

    // 9. 设置 CRTC 使用新的 framebuffer
    if (drmModeSetCrtc(fd, crtc->crtc_id, fb_id, 0, 0, &conn->connector_id, 1,
                       &crtc->mode) < 0)
    {
        perror("Failed to set CRTC");
        goto destroiesframebuffer;
    }

    printf("Drawing complete! Press Enter to exit...\n");
    getchar(); // 等待用户输入，避免立即退出

    result = 0;
    // 10. 清理资源

destroiesframebuffer:
    drmModeRmFB(fd, fb_id);
munmapFramebuffer:
    munmap(framebuffer, create_req.size);
releaseCrtc:
    drmModeFreeCrtc(crtc);
    // releaseEncoder:
    drmModeFreeEncoder(encoder);
    // releaseConnector:
    drmModeFreeConnector(conn);
releaseResources:
    drmModeFreeResources(res);
openFailed:
    close(fd);

    return result;
}